package io.renren.common.wechat;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.emoji.EmojiUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.renren.common.exception.RenException;
import io.renren.common.properties.RenrenProperties;
import io.renren.common.properties.WechatProperties;
import io.renren.common.redis.RedisUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author txb
 */
@Slf4j
@Component
public class WeChatUtil {

    private static String accessToken = "";
    private static long accessTokenTime = 0;
    private static String jsapiTicket = "";
    private static long jsapiTicketTime = 0;
    private static final String APP_ID_SRIT = "wx9d9e6a5943abcb4c";
    private final static String ACCESS_TOKEN = "access_token";
    private final static String JSAPI_TICKET = "ticket";
    public static final int ACCESS_TOKEN_TIME = 7000000;

    @Resource
    private RedisUtils redisUtils;
    @Resource
    private WechatProperties wechatProperties;
    @Resource
    private RenrenProperties renrenProperties;

    /**
     * 获取openid
     *
     * @param code code
     * @return json 包含access_token和openid
     */
    public String getOpenid(String code) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + wechatProperties.getAppId()
                + "&secret=" + wechatProperties.getAppSecret()
                + "&code=" + code + "&grant_type=authorization_code";
        return HttpUtil.get(url, 5000);
    }

    /**
     * 通过openid获取个人信息
     *
     * @param accessToken 通过getOpenid()方法返回的
     * @param openId      通过getOpenid()方法返回的
     * @return json
     */
    public String getUserInfo(String accessToken, String openId) {
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
        return HttpUtil.get(url, 5000);
    }

    /**
     * 获取access_token
     * 如果是公司的测试公众号则不缓存，如果开启了集群环境，则缓存到redis里
     *
     * @return accessToken
     */
    public String getAccessToken() {
        String accessTokenNew = "";
        if (!wechatProperties.getAppId().equals(APP_ID_SRIT)) {
            if (renrenProperties.getRedis().getOpen()) {
                String redisAccessToken = (String) redisUtils.get(ACCESS_TOKEN);
                if (StrUtil.isBlank(redisAccessToken)) {
                    log.info("redis " + ACCESS_TOKEN + "不存在，直接请求微信获取");
                    accessTokenNew = getAccessTokenHttp();
                    log.info("开始更新redis " + ACCESS_TOKEN);
                    redisUtils.set(ACCESS_TOKEN, accessTokenNew, 60 * 60);
                    log.info("更新redis " + ACCESS_TOKEN + "成功");
                } else {
                    log.info("redis " + ACCESS_TOKEN + "存在，直接获取");
                    accessTokenNew = redisAccessToken;
                }
            } else {
                long nowTime = System.currentTimeMillis();
                if (nowTime > accessTokenTime) {
                    // 超时从新获取accessToken
                    accessTokenNew = getAccessTokenHttp();
                    accessToken = accessTokenNew;
                    accessTokenTime = nowTime + ACCESS_TOKEN_TIME;
                } else {
                    accessTokenNew = accessToken;
                }
            }
        } else {
            accessTokenNew = getAccessTokenHttp();
        }
        return accessTokenNew;
    }

    /**
     * 获取access_token
     *
     * @return access_token
     */
    public String getAccessTokenHttp() {
        String accessToken = "";
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + wechatProperties.getAppId()
                + "&secret=" + wechatProperties.getAppSecret();
        String json = HttpUtil.get(url, 5000);
        if (StrUtil.isNotBlank(json)) {
            JSONObject jsonObject = JSONObject.parseObject(json);
            if (jsonObject.containsKey(ACCESS_TOKEN)) {
                accessToken = jsonObject.getString(ACCESS_TOKEN);
                log.info(ACCESS_TOKEN + "获取成功：" + accessToken);
            } else {
                log.error("获取" + ACCESS_TOKEN + "失败：" + json);
                throw new RenException("获取" + ACCESS_TOKEN + "失败");
            }
        } else {
            log.error("获取" + ACCESS_TOKEN + "失败,接口返回空");
            throw new RenException("获取" + JSAPI_TICKET + "失败");
        }
        return accessToken;
    }

    /**
     * 获取jsapi_ticket
     *
     * @param accessToken accessToken
     * @return jsapi_ticket
     */
    public String getJsapiTicket(String accessToken) {
        String jsapiTicketNew = "";
        if (!wechatProperties.getAppId().equals(APP_ID_SRIT)) {
            if (renrenProperties.getRedis().getOpen()) {
                String redisJsapiTicket = (String) redisUtils.get(JSAPI_TICKET);
                if (StrUtil.isBlank(redisJsapiTicket)) {
                    log.info("redis " + JSAPI_TICKET + "不存在，直接请求微信获取");
                    jsapiTicketNew = getJsapiTicketHttp(accessToken);
                    log.info("开始更新redis " + JSAPI_TICKET);
                    redisUtils.set(JSAPI_TICKET, jsapiTicketNew, 60 * 60);
                    log.info("更新redis " + JSAPI_TICKET + "成功");
                } else {
                    log.info("redis " + JSAPI_TICKET + "存在，直接获取");
                    jsapiTicketNew = redisJsapiTicket;
                }
            } else {
                long nowTime = System.currentTimeMillis();
                if (nowTime > accessTokenTime) {
                    // 超时从新获取accessToken
                    jsapiTicketNew = getJsapiTicketHttp(accessToken);
                    jsapiTicket = jsapiTicketNew;
                    jsapiTicketTime = nowTime + ACCESS_TOKEN_TIME;
                } else {
                    jsapiTicketNew = jsapiTicket;
                }
            }
        } else {
            jsapiTicketNew = getJsapiTicketHttp(accessToken);
        }
        return jsapiTicketNew;
    }

    /**
     * 获取jsapi_ticket
     *
     * @param accessToken getAccessTokenHttp()返回的值
     * @return 获取jsapi_ticket
     */
    public String getJsapiTicketHttp(String accessToken) {
        String jsapiTicket = "";
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi";
        String json = HttpUtil.get(url, 5000);
        if (StrUtil.isNotBlank(json)) {
            JSONObject jsonObject = JSONObject.parseObject(json);
            if (jsonObject.containsKey(JSAPI_TICKET)) {
                jsapiTicket = jsonObject.getString(JSAPI_TICKET);
                log.info(JSAPI_TICKET + "获取成功：" + jsapiTicket);
            } else {
                log.error("获取" + JSAPI_TICKET + "失败：" + json);
                throw new RenException("获取" + JSAPI_TICKET + "失败");
            }
        } else {
            log.error("获取" + ACCESS_TOKEN + "失败,接口返回空");
            throw new RenException("获取" + JSAPI_TICKET + "失败");
        }
        return jsapiTicket;
    }

    /**
     * 微信jssdk签名
     *
     * @param state state
     * @param url   url
     * @return map
     */
    public Map<String, String> getJsSdk(String state, String url) {
        if (!url.contains("state=1")) {
            if ("1".equals(state)) {
                url = url + "&state=1";
            }
        }
        String accessToken = getAccessToken();
        String jsapiTicket = getJsapiTicket(accessToken);
        Map<String, String> map = JsapiUtil.sign(jsapiTicket, url);
        map.put("appId", wechatProperties.getAppId());
        return map;
    }

    public String replaceEmoji(String str) {
        str = EmojiUtil.toHtml(str);
        str = str.replaceAll("[^\\u0000-\\uFFFF]", "");
        return str;
    }

    /**
     * 获取openid
     *
     * @return ticket 可以用该ticket生成二维码
     */
    public String createQrCode() {
        String uuid = IdUtil.simpleUUID();
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + accessToken;
        Map<String, Object> map = new HashMap<>(3);
        //有效期，单位秒
        map.put("expire_seconds", 60);
        //二维码类型，QR_SCENE为临时的整型参数值，QR_STR_SCENE为临时的字符串参数值，QR_LIMIT_SCENE为永久的整型参数值，QR_LIMIT_STR_SCENE为永久的字符串参数值
        map.put("action_name", "QR_STR_SCENE");
        Map<String, Object> map1 = new HashMap<>(1);
        map1.put("scene_str", uuid);
        Map<String, Object> map2 = new HashMap<>(1);
        map2.put("scene", map1);
        map.put("action_info", map2);
        String json = JSON.toJSONString(map);

        String result = HttpUtil.post(url, json, 5000);
        if (StrUtil.isBlank(result)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject.containsKey("ticket")) {
            return jsonObject.getString("ticket");
        } else {
            return null;
        }
    }

    /**
     * 接入微信服务器获取加密签名
     *
     * @param token     令牌
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @param encrypt   密文
     * @return 加密签名
     */
    public String getSignature(String token, String timestamp, String nonce, String encrypt) {
        //将token、timestamp、nonce三个参数进行字典序排序
        String[] array = new String[]{token, timestamp, nonce, encrypt};
        StringBuilder stringBuilder = new StringBuilder();
        Arrays.sort(array);
        //将三个参数字符串拼接成一个字符串进行sha1加密
        for (String s : array) {
            stringBuilder.append(s);
        }
        String str = stringBuilder.toString();
        //SHA1签名生成
        return SecureUtil.sha1(str);
    }

    /**
     * 获取公众号菜单
     *
     * @return json
     */
    public String getMenu() {
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=" + accessToken;
        return HttpUtil.get(url, 5000);
    }

    /**
     * 创建公众号菜单
     *
     * @param json 菜单json字符串
     * @return json
     */
    public String createMenu(String json) {
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;
        return HttpUtil.post(url, json, 5000);
    }
}
